package cn.xiaopengstack.domain.strategy.service.raffle;

import cn.xiaopengstack.domain.activity.model.entity.RaffleActivityEntity;
import cn.xiaopengstack.domain.strategy.model.entity.*;
import cn.xiaopengstack.domain.strategy.repository.IStrategyRepository;
import cn.xiaopengstack.domain.strategy.service.armory.IStrategyDispatch;
import cn.xiaopengstack.domain.strategy.service.rule.chain.factory.DefaultLogicChainFactory;
import cn.xiaopengstack.domain.strategy.service.rule.tree.impl.DefaultTreeFactory;
import cn.xiaopengstack.types.enums.ResponseCode;
import cn.xiaopengstack.types.exception.AppException;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;

/**
 * @author jiangyangang
 * 抽象抽奖策略
 */
@Slf4j
public abstract class AbstractRaffleStrategy implements IRaffleStrategy, IRaffleStock, IRaffleAward{

    // 策略仓储服务 -> domain层像一个大厨，仓储层提供米面粮油
    protected IStrategyRepository strategyRepository;
    // 策略调度服务 -> 只负责抽奖处理，通过新增接口的方式，隔离职责，不需要使用方关心或者调用抽奖的初始化
    protected IStrategyDispatch strategyDispatch;
    // 责任链工厂
    protected DefaultLogicChainFactory defaultLogicChainFactory;
    // 规则树工厂
    protected DefaultTreeFactory defaultTreeFactory;

    public AbstractRaffleStrategy(IStrategyRepository strategyRepository, IStrategyDispatch strategyDispatch, DefaultLogicChainFactory defaultLogicChainFactory, DefaultTreeFactory defaultTreeFactory) {
        this.strategyRepository = strategyRepository;
        this.strategyDispatch = strategyDispatch;
        this.defaultLogicChainFactory = defaultLogicChainFactory;
        this.defaultTreeFactory = defaultTreeFactory;
    }

    @Override
    public RaffleAwardEntity doRaffle(RaffleFactorEntity raffleFactorEntity) {
        // 参数校验
        if (StringUtils.isEmpty(raffleFactorEntity.getUser().getUserId()) || null == raffleFactorEntity.getActivityEntity()) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }

        StrategyEntity strategyEntity = strategyRepository.queryStrategyEntityByStrategyId(raffleFactorEntity.getActivityEntity().getStrategyId());

        // 执行前置链接的责任链
        DefaultLogicChainFactory.StrategyAwardVO chainStrategyAwardVO = raffleLogicChain(RaffleStrategyContext.buildLogicChain(strategyEntity,
                raffleFactorEntity.getUser(),
                raffleFactorEntity.getActivityEntity()));
        log.info("抽奖策略计算-责任链 {} {} {} {}", raffleFactorEntity.getUser().getUserId(), raffleFactorEntity.getActivityEntity().getStrategyId(), chainStrategyAwardVO.getAwardId(), chainStrategyAwardVO.getTakeOverRule());
        // 前置责任链规则未执行到抽奖节点，直接范围兜底奖励
        Integer awardId;
        if (DefaultLogicChainFactory.LogicModel.RULE_DEFAULT != chainStrategyAwardVO.getTakeOverRule()) {
            awardId = chainStrategyAwardVO.getAwardId();
        } else {
            // 执行奖励的规则树
            DefaultTreeFactory.StrategyAwardVO treeAwardVo = raffleLogicTree(RaffleStrategyContext.buildLogicTree(strategyEntity,
                    raffleFactorEntity.getUser(),
                    raffleFactorEntity.getActivityEntity(),
                    chainStrategyAwardVO.getAwardId()));
            log.info("抽奖策略计算-规则树 {} {} {} {}", raffleFactorEntity.getUser().getUserId(), raffleFactorEntity.getActivityEntity().getStrategyId(), treeAwardVo.getAwardId(), treeAwardVo.getAwardRuleValue());
            awardId = treeAwardVo.getAwardId();
        }

        // 查询奖品信息
        StrategyAwardEntity awardEntity = strategyRepository.queryStrategyAward(strategyEntity.getStrategyId(), awardId);

        // 返回抽奖结果
        return RaffleAwardEntity.builder()
                .strategyEntity(strategyEntity)
                .awardEntity(awardEntity)
                .awardTime(new Date())
                .build();
    }

    /**
     * 奖品责任链执行
     * @param context
     * @return
     */
    protected abstract DefaultLogicChainFactory.StrategyAwardVO raffleLogicChain(RaffleStrategyContext context);

    /**
     * 奖品规则树执行
     * @param context
     * @return
     */
    protected abstract DefaultTreeFactory.StrategyAwardVO raffleLogicTree(RaffleStrategyContext context);


    @Getter
    @Setter
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class RaffleStrategyContext{
        private UserEntity userEntity;
        private StrategyEntity strategyEntity;
        private Integer awardId;
        private RaffleActivityEntity activityEntity;

        /**
         * 构造责任链上下文
         * @param strategyEntity
         * @param userEntity
         * @param raffleActivityEntity
         * @return
         */
        public static RaffleStrategyContext buildLogicChain(StrategyEntity strategyEntity, UserEntity userEntity, RaffleActivityEntity raffleActivityEntity){
            return RaffleStrategyContext.builder()
                    .strategyEntity(strategyEntity)
                    .userEntity(userEntity)
                    .activityEntity(raffleActivityEntity)
                    .build();
        }

        /**
         * 构造责任链上下文
         * @param strategyEntity
         * @param userEntity
         * @return
         */
        public static RaffleStrategyContext buildLogicTree(StrategyEntity strategyEntity, UserEntity userEntity, RaffleActivityEntity raffleActivityEntity, Integer awardId){
            return RaffleStrategyContext.builder()
                    .strategyEntity(strategyEntity)
                    .userEntity(userEntity)
                    .activityEntity(raffleActivityEntity)
                    .awardId(awardId)
                    .build();
        }
    }


}
